package org.zhangsh.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * </p>
 *
 * @author zhangsh
 * @version 1.0.0
 * @since 2019-04-17
 */
public class NioServerSocketDemo {

    private Selector selector = null;

    public void initServer(int port) throws IOException {

        // 创建服务端socket通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 初始化服务端socket通道属性，设置阻塞，绑定端口
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(port));

        // 初始化一个通道管理器 selector
        selector = Selector.open();
        // 服务socket端通道往selector注册一个“获取客户端获取请求的事件”
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务端启动成功...");

    }

    public void listenSelector() throws IOException{

        while(true){
            // socket通道管理器，当有事件来时，就获取，否则阻塞
            selector.select();

            Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
            while(iterator.hasNext()){

                SelectionKey selectionKey = iterator.next();
                iterator.remove();

                handlerKey(selectionKey);
            }
        }

    }

    private void handlerKey(SelectionKey selectionKey) throws IOException{

        // 判断这个事件的类型，
        if(selectionKey.isAcceptable()){
            System.out.println(Thread.currentThread().getName() + "新的客户端连接事件到来...");
            ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
            SocketChannel socketChannel = serverSocketChannel.accept();
            socketChannel.configureBlocking(false);
            socketChannel.register(this.selector, SelectionKey.OP_READ);
        }else if(selectionKey.isReadable()){

            System.out.println(Thread.currentThread().getName() + "新的读事件到来...");
            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
            socketChannel.configureBlocking(false);

            // 创建读取的缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);//1kb
            int readData = socketChannel.read(buffer);
            if(readData > 0){
                String msg = new String(buffer.array(),"GBK").trim();// 先讲缓冲区数据转化成byte数组,再转化成String
                System.out.println(Thread.currentThread().getName() + "服务端收到信息：" + msg);

                //回写数据
                ByteBuffer writeBackBuffer = ByteBuffer.wrap("receive data".getBytes("GBK"));
                socketChannel.write(writeBackBuffer);// 将消息回送给客户端
            }else{
                System.out.println(Thread.currentThread().getName() + "客户端关闭咯...");
                //SelectionKey对象会失效，这意味着Selector再也不会监控与它相关的事件
                selectionKey.cancel();
            }

        }else if(selectionKey.isConnectable()){
            System.out.println(Thread.currentThread().getName() + "连接就绪");
        }

    }

    public static void main(String[] args) throws IOException{
        NioServerSocketDemo demo = new NioServerSocketDemo();

        demo.initServer(7777);
        demo.listenSelector();
    }
}
